package com.superhero.miniprogram.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.superhero.common.exception.BusinessException;
import com.superhero.common.pojo.PageInput;
import com.superhero.common.pojo.entity.AccessRegistration;
import com.superhero.common.pojo.entity.AuthUser;
import com.superhero.common.pojo.entity.UserHealthInfo;
import com.superhero.common.pojo.vo.HealthInfoInput;
import com.superhero.common.pojo.vo.HealthInfoVo;
import com.superhero.common.pojo.vo.PageVo;
import com.superhero.common.pojo.vo.UserEnd.AccessInfoListVo;
import com.superhero.common.pojo.vo.UserEnd.UserInfoVo;
import com.superhero.common.repository.AccessRegistrationRepository;
import com.superhero.common.repository.AuthUserRepository;
import com.superhero.common.repository.UserHealthInfoRepository;
import com.superhero.common.utils.OptionalUtil;
import com.superhero.miniprogram.config.WxConfiguration;
import com.superhero.miniprogram.config.WxProperties;
import com.superhero.miniprogram.security.UserUtil;
import com.superhero.miniprogram.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StreamUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;



@Service
@ComponentScan(basePackages = "com.superhero")
public class UserServiceImpl implements UserService {

    @Autowired
    private AuthUserRepository authUserRepository;
    @Autowired
    private UserHealthInfoRepository userHealthInfoRepository;
    @Autowired
    private AccessRegistrationRepository accessRegistrationRepository;

    @Resource
    private WxProperties properties;
    @Value("${wx.miniapp.path")
    String path;
    @Value("${upload.website}")
    String website;

    @Override
    public UserInfoVo getHealthQRCode(String username) {
        AuthUser authUser = authUserRepository.findAuthUserByUsername(username).get();
        if (authUser.getLocked() == 1)
            throw new BusinessException("对不起，您的账号已被锁定。");
        UserInfoVo userInfoVo = new UserInfoVo();
        userInfoVo.setUsername(authUser.getUsername());
        userInfoVo.setAvatarUrl(authUser.getAvatarUrl());
        userInfoVo.setQrcode(authUser.getQrcode());
        if (authUser.getRole() == 0) {
            userInfoVo.setVerify(0);
        } else {
            userInfoVo.setVerify(1);
        }

        UserHealthInfo userHealthInfo = authUser.getUserHealthInfo();
        if (userHealthInfo == null) { // 未填写健康表
            userInfoVo.setAddress(null);
//            userInfoVo.setStatus();
            return userInfoVo;
        }
        userInfoVo.setAddress(userHealthInfo.getAddress());
        Integer symptoms = userHealthInfo.getSymptomsWithin14day();
        Integer observation = userHealthInfo.getIsolationObservation();
        Integer normal = userHealthInfo.getNormalTemperature();
        if (userHealthInfo.getConfirmed() == 1) {
            userInfoVo.setStatus(2);
        } else {
            if (normal == 1 && symptoms + observation == 0) {
                userInfoVo.setStatus(0);
            } else {
                userInfoVo.setStatus(1);
            }
        }

        return userInfoVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createHealthInfo(String username, HealthInfoInput input) {
        AuthUser authUser = authUserRepository.findAuthUserByUsername(username).get();
        if (authUser.getLocked() == 1)
            throw new BusinessException("对不起，您的账号已被锁定。");
        UserHealthInfo userHealthInfo = new UserHealthInfo();
        BeanUtils.copyProperties(input, authUser);
        authUserRepository.save(authUser);
        BeanUtils.copyProperties(input, userHealthInfo);
        userHealthInfo.setUserId(authUser.getId());

        Integer symptoms = input.getSymptomsWithin14day();
        Integer observation = input.getIsolationObservation();
        Integer normal = input.getNormalTemperature();
        if (normal == 1 && symptoms == 0 && observation == 0)
            userHealthInfo.setConfirmed(1);
        else userHealthInfo.setConfirmed(0);
        userHealthInfoRepository.save(userHealthInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void UpdateHealthInfo(String username, HealthInfoInput input) {
        AuthUser authUser = authUserRepository.findAuthUserByUsername(username).get();
        if (authUser.getLocked() == 1)
            throw new BusinessException("对不起，您的账号已被锁定。");
        UserHealthInfo userHealthInfo = authUser.getUserHealthInfo();
        BeanUtils.copyProperties(input, authUser);
        BeanUtils.copyProperties(input, userHealthInfo);
        Integer symptoms = input.getSymptomsWithin14day();
        Integer observation = input.getIsolationObservation();
        Integer normal = input.getNormalTemperature();
        if (normal == 1 && symptoms == 0 && observation == 0)
            userHealthInfo.setConfirmed(1);
        else userHealthInfo.setConfirmed(0);

        authUserRepository.save(authUser);
        userHealthInfoRepository.save(userHealthInfo);
    }


    @Override
    public HealthInfoVo getHealthInfo(String username) {
        AuthUser authUser = OptionalUtil.get(authUserRepository.findAuthUserByUsername(username));
        if (authUser.getLocked() == 1)
            throw new BusinessException("对不起，您的账号已被锁定。");
//        UserHealthInfo userHealthInfo = OptionalUtil.get(userHealthInfoRepository.findByUserId(authUser.getId()));
        UserHealthInfo userHealthInfo = authUser.getUserHealthInfo();
        if (userHealthInfo == null)
            throw new BusinessException("您还未填写健康登记表！");
        HealthInfoVo healthInfoVo = new HealthInfoVo();
        BeanUtils.copyProperties(userHealthInfo, healthInfoVo);
        healthInfoVo.setRealName(authUser.getRealName());
        healthInfoVo.setIdCard(authUser.getIdCard());
        healthInfoVo.setPhone(authUser.getPhone());

        return healthInfoVo;
    }

    @Override
    public PageVo getAccessInfoList(PageInput pageInput, String keyword) {
        Integer id = UserUtil.getUserId();
        Pageable pageable = PageRequest.of(pageInput.getPageNumber(), pageInput.getPageSize());
        // 获取所有ID为当前UserId的出入数据
        Page<AccessRegistration> accessRegistrations = accessRegistrationRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            predicates.add(criteriaBuilder.equal(root.join("user").get("id"), id));
            if (!StringUtils.isEmpty(keyword)) {
                String key = "%" + keyword.trim() + "%";
                String upperKey = "%" + keyword.toUpperCase().trim() + "%";
                // key可为人员姓名、检查人员姓名、出入类型（出/入），检查人员手机号，社区名称的全模糊查询
                Predicate p1 = null, p2 = null, p3 = null, p4 = null, p5 = null;
                p1 = criteriaBuilder.like(criteriaBuilder.upper(root.join("user").get("username")), upperKey);
                p5 = criteriaBuilder.like(root.join("user").get("userHealthInfo").get("communityLocation"), upperKey);
                if ("出".equals(keyword.trim())) {
                    p3 = criteriaBuilder.equal(root.get("inOrOut").as(Integer.class), 0);
                    predicates.add(criteriaBuilder.or(p1, p2, p3, p4, p5));
                } else if ("入".equals(keyword.trim())) {
                    p3 = criteriaBuilder.equal(root.get("inOrOut").as(Integer.class), 1);
                    predicates.add(criteriaBuilder.or(p1, p2, p3, p4, p5));
                } else {
                    predicates.add(criteriaBuilder.or(p1, p2, p4, p5));
                }
            }
            Predicate[] p = new Predicate[predicates.size()];
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            return criteriaBuilder.and(predicates.toArray(p));
        }, pageable);

        PageVo result = PageVo.convert(accessRegistrations);
        result.setContent(accessRegistrations.getContent().stream()
                .map(accessRegistration -> {
                    AccessInfoListVo accessInfoListVo = new AccessInfoListVo();
                    BeanUtils.copyProperties(accessRegistration, accessInfoListVo);
                    accessInfoListVo.setInspectorName(accessRegistration.getInspector().getRealName());
                    accessInfoListVo.setInspectorPhone(accessRegistration.getInspector().getPhone());
                    accessInfoListVo.setCommunityLocation(accessRegistration.getUser().getUserHealthInfo().getCommunityLocation());
                    return accessInfoListVo;
                }).collect(Collectors.toList()));
        return result;
    }


    /**
     * 保存二维码地址
     *
     * @param id
     * @throws Exception
     */
    private String createQRcode(Integer id) throws Exception {
        final WxMaService wxService = WxConfiguration.getMaService(properties.getConfigs().get(0).getAppid());
        File file = wxService.getQrcodeService().createWxaCodeUnlimit(String.valueOf(id), path);
        FileInputStream inputStream = new FileInputStream(file);
        String suffix = file.getName().substring(file.getName().lastIndexOf(".") + 1);
        String filename = "QRCODE" + File.separator + UUID.randomUUID() + "." + suffix;

        File newFile = new File(path + File.separator + filename);
        File parentFile = newFile.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        FileOutputStream fileOutputStream = new FileOutputStream(newFile);
        StreamUtils.copy(inputStream, fileOutputStream);
        return website + filename;
    }
}
